package model;


public class RoffTriangle {
    private int p1;
    private int p2;
    private int p3;
    private double distance;
    private RoffVector3D viewVector;
    private RoffVector3D normal;
    private RoffVector3D centroid;
    private RoffVector3D[] pointArray;
    private double maxX; 
    private double minX; 
    private double maxY; 
    private double minY; 
    private double maxZ; 
    private double minZ;
    private int[] order; 
    public RoffTriangle(int point1, int point2, int point3, RoffVector3D[] newPointArray) {
        p1 = point1;
        p2 = point2;
        p3 = point3;
        pointArray = newPointArray; 
        minX=GeoUtil.min(pointArray[p1].x, pointArray[p2].x, pointArray[p3].x);
        maxX=GeoUtil.max(pointArray[p1].x, pointArray[p2].x, pointArray[p3].x);
        minY=GeoUtil.min(pointArray[p1].y, pointArray[p2].y, pointArray[p3].y);
        maxY=GeoUtil.max(pointArray[p1].y, pointArray[p2].y, pointArray[p3].y);
        minZ=GeoUtil.min(pointArray[p1].z, pointArray[p2].z, pointArray[p3].z);
        maxZ=GeoUtil.max(pointArray[p1].z, pointArray[p2].z, pointArray[p3].z);
        order=new int[3];
		Pair[] p=new Pair[]{new Pair(RoffVector3D.X,maxX-minX),new Pair(RoffVector3D.Y,maxY-minY),new Pair(RoffVector3D.Z,maxZ-minZ)};
		java.util.Arrays.sort(p);
		for (int i=0; i<3; i++){
			order[i]=p[i].index; 
			//System.out.println(i+")"+p[i].value+"/"+p[i].index); 
		}
        buildCentroid();
        buildNormal();
    }
    public RoffVector3D getPoint1(){
    	return pointArray[p1]; 
    }
    public RoffVector3D getPoint2(){
    	return pointArray[p2]; 
    }
    public RoffVector3D getPoint3(){
    	return pointArray[p3]; 
    }    
    public int getP1() {
        return p1;
    }
	
    public int getP2() {
        return p2;
    }

    public int getP3() {
        return p3;
    }

    public RoffVector3D getView() {
        return new RoffVector3D(viewVector.x , viewVector.y, viewVector.z);
    }

    public RoffVector3D getNormal() {
        return new RoffVector3D(normal.x, normal.y, normal.z);
    }

    public RoffVector3D getCentroid() {
        return new RoffVector3D(centroid.x, centroid.y, centroid.z);
    }

    public void rebuild() {
    	buildCentroid();
    	buildNormal();
    }

    public void updateView(RoffVector3D fromPoint, RoffVector3D LoS) {

        viewVector = fromPoint.sub(centroid);
        distance = (centroid.sub(fromPoint)).dot(LoS);
        viewVector.normalize();
    }

    public boolean closer(RoffTriangle rhs) {
        return distance < rhs.distance;
    }

    public boolean sameDepth(RoffTriangle rhs) {
        return distance == rhs.distance;
    }

    public double getDepth() {
        return distance;
    }

    private void buildCentroid() {
	centroid = (
                    ( (pointArray[p1]).add(pointArray[p2])
                    ).add(pointArray[p3])
                   ).scalarDivide(3.0);
    }

    private void buildNormal() {
        normal = (
                  (pointArray[p2]).sub(pointArray[p1])
                 ).cross(
                  (pointArray[p3]).sub(pointArray[p1])
                 );
        normal.normalize();
    }
	public double getMaxX() {
		return maxX;
	}
	public double getMinX() {
		return minX;
	}
	public double getMaxY() {
		return maxY;
	}
	public double getMinY() {
		return minY;
	}
	public double getMaxZ() {
		return maxZ;
	}
	public double getMinZ() {
		return minZ;
	}
	public int[] getOrder() {
		return order;
	}
	public double getArea(){
		RoffVector3D p1=this.getPoint1();
		RoffVector3D p2=this.getPoint2();
		RoffVector3D p3=this.getPoint3();
		double x1=p1.x; 
		double y1=p1.y; 
		double z1=p1.z; 
		double x2=p2.x; 
		double y2=p2.y; 
		double z2=p2.z; 
		double x3=p3.x; 
		double y3=p3.y; 
		double z3=p3.z; 

		
		double a_2=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2);
		double b_2=(x1-x3)*(x1-x3)+(y1-y3)*(y1-y3)+(z1-z3)*(z1-z3);
		double c_2=(x3-x2)*(x3-x2)+(y3-y2)*(y3-y2)+(z3-z2)*(z3-z2);
		double area=(a_2+b_2+c_2)*(a_2+b_2+c_2)-2*(a_2*a_2+b_2*b_2+c_2*c_2);
		if (area<0){
			//System.out.println(area);
			//throw new RuntimeException("negative area");
			area=0; 
		}
		return Math.sqrt(area)/4.0;  
	}
	public static class Pair implements Comparable<Pair>{
		public int index;
		public double value;
		public Pair(int i, double v){
			index=i; 
			value=v; 
		}
		@Override
		public int compareTo(Pair p) {
			if (value>p.value){
				return -1; 
			}else {
				return 1; 
			}
		}
	}
}
